﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using EPiBoost.Core.Model.Enums;
using EPiServer;

namespace EPiBoost.Core.Model
{
	public class Pagination
	{
		public int TotalPages { get; set; }
		public int CurrentPageIndex { get; set; }
		public string PageIndexQueryStringKey { get; set; }

		public bool ShowPageLinks { get; set; }
		public string PageLinkFormat { get; set; }
		public string PageLinkSeperatorText { get; set; }
		
		public int MovingWindowSize { get; set; }
		public int LeftLinkWindowSize { get; set; }
		public int RightLinkWindowSize { get; set; }
		public string WindowSeperatorText { get; set; }

		public string PreviousLinkText { get; set; }
		public bool ShowPreviousLink { get; set; }
		public bool AutoHidePreviousLink { get; set; }

		public string NextLinkText { get; set; }
		public bool ShowNextLink { get; set; }
		public bool AutoHideNextLink { get; set; }



		public Pagination(string pageIndexQueryStringKey = "pg", int totalPages = 0, int currentPageIndex = 0)
		{
			PageIndexQueryStringKey = pageIndexQueryStringKey;
			TotalPages = totalPages;
			CurrentPageIndex = currentPageIndex;

			ShowPageLinks = true;
			ShowNextLink = true;
			ShowPreviousLink = true;
			PreviousLinkText = "Previous"; // todo : add xml language support
			NextLinkText = "Next"; // todo : add xml language support
			PageLinkFormat = "{0}";
			WindowSeperatorText = "...";
		}

		public IEnumerable<PaginationNode> GetLinks()
		{
			var nodes = new List<PaginationNode>();

			if (ShowPreviousLink)
			{
				AddPreviousLink(nodes);
			}

			if (ShowPageLinks)
			{
				if (MovingWindowSize > 0)
				{
					AddLinkWindow(nodes);
				}
				else
				{
					AddPageLinks(nodes, 0, TotalPages);
				}
			}

			if (ShowNextLink)
			{
				AddNextLink(nodes);
			}

			return nodes;
		}

		private void AddLinkWindow(List<PaginationNode> nodes)
		{
			int windowStart = CurrentPageIndex - (int)(Math.Ceiling((double)MovingWindowSize / 2)) + 1;
			if (windowStart + MovingWindowSize > TotalPages)
			{
				windowStart = TotalPages - MovingWindowSize;
			}
			windowStart = Math.Max(0, windowStart);
			int windowSize = Math.Min(MovingWindowSize, TotalPages - windowStart );



			// left
			if(LeftLinkWindowSize > 0)
			{
				int leftSize = Math.Min(windowStart, LeftLinkWindowSize);
				if (leftSize == windowStart) // to include text seperator
				{
					windowStart = 0;
					windowSize += leftSize;
				}
				else
				{
					AddPageLinks(nodes, 0, leftSize);
					if (!string.IsNullOrEmpty(WindowSeperatorText))
					{
						nodes.Add(new PaginationNode{NodeType = PaginationNodeType.WindowSeperator, Text = WindowSeperatorText});
					}
				}
			}

			// right
			bool addRight = false; 
			if (RightLinkWindowSize > 0)
			{
				int windowEnd = windowStart + windowSize;
				int rightStart = TotalPages - RightLinkWindowSize;
				int rightSize = Math.Min(TotalPages - windowEnd, RightLinkWindowSize);
				if (windowEnd >= rightStart)
				{
					windowSize += rightSize;
					windowStart = TotalPages - windowSize;
				}
				else
				{
					addRight = true;
				}
			}


			// center
			AddPageLinks(nodes, windowStart, windowSize);

			if(addRight)
			{
				if (!string.IsNullOrEmpty(WindowSeperatorText))
				{
					nodes.Add(new PaginationNode{ NodeType = PaginationNodeType.WindowSeperator, Text = WindowSeperatorText });
				}
				AddPageLinks(nodes, TotalPages - RightLinkWindowSize, RightLinkWindowSize);
			}
			

		}
		 


		private void AddPageLinks(List<PaginationNode> nodes, int startIndex, int count)
		{
			int stopIndex = startIndex + count;
			for (int i = startIndex; i < stopIndex; i++)
			{
				var linkText = string.Format(PageLinkFormat, i+1);
				if (i == CurrentPageIndex)
				{
					nodes.Add(new PaginationNode{Text = linkText, NodeType = PaginationNodeType.CurrentPageLink});
				}
				else
				{
					nodes.Add(new PaginationNode { Text = linkText, NodeType = PaginationNodeType.PageLink, LinkUrl = GetLinkUrl(i) });
				}

				if(!string.IsNullOrEmpty(PageLinkSeperatorText) && i< stopIndex-1)
				{
					nodes.Add(new PaginationNode { Text = PageLinkSeperatorText, NodeType = PaginationNodeType.LinkSeperator, LinkUrl = GetLinkUrl(i) });
				}
			}
		}

		private void AddPreviousLink(List<PaginationNode> nodes)
		{ 
			if(CurrentPageIndex>0)
			{
				nodes.Add(new PaginationNode{Text = PreviousLinkText, NodeType = PaginationNodeType.PreviousLink, LinkUrl = GetLinkUrl(CurrentPageIndex-1)});
			}
			else if(!AutoHidePreviousLink)
			{
				nodes.Add(new PaginationNode{Text = PreviousLinkText, NodeType = PaginationNodeType.PreviousLink});
			} 
		}

		private void AddNextLink(List<PaginationNode> nodes)
		{
			if (CurrentPageIndex < TotalPages - 1)
			{
				nodes.Add(new PaginationNode
				          	{Text = NextLinkText, NodeType = PaginationNodeType.NextLink, LinkUrl = GetLinkUrl(CurrentPageIndex + 1)});
			}
			else if (!AutoHideNextLink)
			{
				nodes.Add(new PaginationNode {Text = NextLinkText, NodeType = PaginationNodeType.NextLink});
			}
		}

		private string GetLinkUrl(int pageIndex)
		{
			if(HttpContext.Current!=null)
			{
				var builder = new UrlBuilder(HttpContext.Current.Request.Url);
				builder.QueryCollection.Set(PageIndexQueryStringKey, pageIndex.ToString());
				return builder.ToString();
			}
			return null;
		} 

	}
}
